package com.atguigu.tingshu.common.minio.service.impl;

import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.minio.config.MinioProperties;
import com.atguigu.tingshu.common.minio.service.FileUploadService;
import com.atguigu.tingshu.common.util.MD5;
import io.minio.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.ErrorResponseException;
import org.springframework.web.multipart.MultipartFile;

/**
 * ClassName: FileUploadServiceImpl
 * Package: com.atguigu.tingshu.album.service.impl
 * Description:
 *
 * @Author 梅超凡
 * @Create 2025/1/14 18:42
 * @Version 1.0
 */
@Slf4j
//@Service
public class FileUploadServiceImpl implements FileUploadService {

    @Autowired
    private MinioProperties properties;

    @Autowired
    private MinioClient client;


    @Override
    public String fileUpload(MultipartFile file) {


        String originalFilename = file.getOriginalFilename();
        try {
            //判断存储桶是否存在
            boolean bucketExists = client.bucketExists(
                    BucketExistsArgs.builder().bucket(
                            properties.getBucketName()).build());
            //如果不存在就创建
            if (!bucketExists) {
                //开始创建桶
                client.makeBucket(
                        //创建桶的参数
                        MakeBucketArgs
                                .builder()
                                .bucket(
                                        //桶名
                                        properties.getBucketName()).build());
                //设置桶的权限策略
                client.setBucketPolicy(
                        //设置桶权限的参数
                        SetBucketPolicyArgs
                                .builder()
                                .bucket(properties.getBucketName())
                                .config(
                                        //创建桶的权限策略配置（参数桶名）
                                        createBucketPolicyConfig(properties.getBucketName())
                                ).build());
            }
            // 1.获取文件对象字节数组
            byte[] bytes = file.getBytes();
            // 1.1.将字节数组转成字符串
            String fileContentStr = new String(bytes);
            // 1.2.将字符串进行MD5加密
            String filePrefix = MD5.encrypt(fileContentStr);
            // 1.3.获取文件的后缀
            String fileSuffix = originalFilename.substring(
                    originalFilename.lastIndexOf("."), originalFilename.length());
            // 1.4.定义对象名
            String pictureName = filePrefix + fileSuffix;
            // 2.对文件对象进行去重校验
            StatObjectArgs statObjectArgs = StatObjectArgs
                    .builder()
                    .bucket(properties.getBucketName())// 桶名
                    .object(pictureName)// 图片名
                    .build();
            try{
                client.statObject(statObjectArgs);// 如果不抛出异常，则代表minio指定桶中的文件已经存在，反之对象不存在
                log.info("minio指定桶中的对象存在，不用上传，直接返回对象在mino中的地址");
                return  properties.getEndpointUrl() + "/" + properties.getBucketName() + "/" + pictureName;
            }catch (Exception e){
                log.info("minio指定桶中的对象不存在，可以上传");
                // 3.上传
                // 3.1 构建一个PutObjectArgsBuilder对象
                PutObjectArgs.Builder builder = PutObjectArgs.builder();
                PutObjectArgs putObjectArgs = builder
                        .bucket(properties.getBucketName())
                        .object(pictureName)
                        .stream(file.getInputStream(), file.getSize(), -1)
                        .build();
                // 3.2 真正上传
                client.putObject(putObjectArgs);
                // 文件地址：虚拟机的ip地址:虚拟机的端口/桶的名字/对象名
                return  properties.getEndpointUrl() + "/" + properties.getBucketName() + "/" + pictureName;
            }
        }catch (Exception e) {
            log.error("文件上传到minio中失败：{}", e.getMessage());
            throw new GuiguException(201, "文件上传到minio中失败");
        }
    }

    /**
     * 创建minio桶的权限策略
     *
     * @param bucketName
     * @return String
     */
    private String createBucketPolicyConfig(String bucketName) {

        return """
            {
              "Statement" : [ {
                "Action" : "s3:GetObject",
                "Effect" : "Allow",
                "Principal" : "*",
                "Resource" : "arn:aws:s3:::%s/*"
              } ],
              "Version" : "2012-10-17"
            }
            """.formatted(bucketName);
    }
}
